/* 
 * File:   StackList.h
 * Author: Gab'z
 *
 * Created on 28 mai 2012, 11:39
 */

#ifndef STACKLIST_H
#define	STACKLIST_H

#include <list>
#include "Stack.h"
#include "../../../exception/ContextException.h"
#include "../../../log/LogSystem.h"

namespace calculator {

    /**
     * Classe conteneur de Stack.
     * Maintient à jour un itérateur vers la Stack courante du Context.
     */
    class StackList {
        
        /**
         * Amitié avec XMLParser pour faciliter la manipulation de la StackList.
         * Entorse à l'encapsulation volontaire (manque de temps et côté pratique,
         * plus rapide que de réimplémeter un itérateur, on aurait aussi pu 
         * hériter de std::list).
         */
        friend class XMLParser;

    public:

        /**
         * Singleton StackList.
         * @return crée et/ou renvoie l'unique instance de StackList.
         */
        static StackList* getInstance();

        /**
         * Singleton StackList.
         * Détruit l'unique instance de StackList.
         * Libère la mémoire utilisée par toutes les Stack.
         */
        static void deleteInstance();

        /**
         * Destructeur de StackList.
         */
        virtual ~StackList();

        /**
         * Clone l'ensemble des Stack.
         * @return une copie des Stack.
         */
        StackList* clone() const;

        /**
         * Getter vers la Stack désignée.
         * lance une ContextException si l'index sort de la liste.
         * index : [0 ; size() - 1].
         * @param n l'index de la Stack désirée parmi la StackList.
         * @return la Stack désignée.
         */
        Stack* getStack(const unsigned int n) const throw (ContextException);

        /**
         * Getter vers la Stack courante.
         * @return la Stack courante du Context.
         */
        Stack* getCurrentStack() const;

        /**
         * Setter de la Stack courante.
         * lance une ContextException si l'index sort de la liste.
         * index : [0 ; size() - 1].
         * @param n index de la Stack contenue dans la StackList.
         */
        void setCurrentStack(const unsigned int n) throw (ContextException);

        /**
         * Getter de l'index de la Stack courante parmi la StackList.
         * @return index de la Stack courante.
         */
        unsigned int getCurrentStackIndex() const;

        /**
         * Ajoute une Stack à la fin de la StackList.
         * Place l'itérateur de la pile courante sur cette nouvelle Stack
         * Si aucune Stack en argument, on en crée une nouvelle, sinon on la copie.
         * @param stack une Stack à copier
         */
        void newStack(const Stack* stack = 0);

        /**
         * Supprime de la mémoire la Stack courante.
         * Déplace l'itérateur sur la Stack suivante si elle existe, la précédente sinon.
         */
        void removeCurrentStack();

        /**
         * Duplique la Stack courante et la place après cette dernière.
         * Déplace l'itérateur de la Stack courante vers la nouvelle Stack.
         */
        void duplicateCurrentStack();

        /**
         * Insère la Stack à l'index spécifié dans la StackList.
         * Place l'itérateur sur cette nouvelle Stack.
         * Ne crée pas de copie de la Stack.
         * Si l'index est hors de la liste, l'insertion sera faite à la fin de la StackList
         * @param stack la stack à insérer dans la StackList
         * @param index la position d'insertion
         */
        void insertStackAtIndex(Stack* stack, const unsigned int index);

        /**
         * Indique si la StackList est vide ou non.
         * @return true si la StackList est vide, false sinon.
         */
        bool empty() const;

        /**
         * Nombre de Stack contenues dans la StackList
         * @return le nombre de Stack contenues dans la StackList
         */
        unsigned int size() const {
            return _stackList.size();
        }

    private:

        /**
         * instance du Singleton StackList.
         */
        static StackList* instance;

        /**
         * Conteneur de Stack
         */
        std::list<Stack*> _stackList;

        /**
         * Itérateur vers la Stack courante
         */
        std::list<Stack*>::iterator _iteratorCurrentStack;

        /**
         * Constructeur de StackList
         */
        StackList();
        
        static Logger* log;
    };
}

#endif	/* STACKLIST_H */

